#include <iostream>
#include <unistd.h>
#include <vector>
#include <cassert>
#include <ctime>
#include "task.hpp"
#include <sys/wait.h>
#include <sys/types.h>
using namespace std;

const size_t PROCESS_NUM = 5;

uint32_t WaitCommand(int rfd){
    uint32_t comid = 0;
    ssize_t sz = read(rfd, &comid, sizeof(comid));
    if(sz == 0)
    {
        return -1;
    }
    assert(sz == sizeof(uint32_t));
    return comid;
}

void SendAndWakeup(pid_t cpid, int wfd, uint32_t cmdid){
    write(wfd, &cmdid, sizeof(cmdid));
    printf("main process: call %d execute %s through %d\n", cpid, desc[cmdid].c_str(), wfd);
}

int main(){
    srand(time(nullptr));
    LoadHandler();
    //1.创建一个进程信道表：pid-fd
    vector<pair<pid_t, int>> slots;

    //2.循环创建子进程并建立管道通信，填写进程信道表
    for(size_t i = 0; i < PROCESS_NUM; ++i)
    {
        //2.1 创建管道
        int pipefd[2] = {0};
        int ret = pipe(pipefd);
        assert(ret!=-1);
        (void)ret;

        //2.2 创建子进程
        pid_t id = fork();
        assert(id!=-1);
        if(id == 0)
        {
            //3. 子进程接收并执行命令
            close(pipefd[1]); //关闭写端
            while(true)
            {
                uint32_t comid = WaitCommand(pipefd[0]); //如果对方不发送命令，就阻塞等待
                if(comid >= 0 && comid < cmdset.size()) //如果comid合法就执行命令
                {
                    cmdset[comid]();
                }
                else if(comid == -1) //写端关闭，子进程退出
                {
                   break;
                }
                else
                {   
                  cout << "非法的命令ID！" << endl;
                }
            }
            
            exit(0);
        }

        //2.3 填写进程信道表
        close(pipefd[0]);
        slots.emplace_back(id, pipefd[1]);
    }

    //父进程选择进程发送命令
    while(true)
    {
        //随机任务
        uint32_t cmdid = rand() % cmdset.size();
        int choice = rand() % slots.size();
        SendAndWakeup(slots[choice].first, slots[choice].second, cmdid);
        sleep(1);
        
        //手动指派任务
        // int select;
        // uint32_t cmdid;
        // cout << "############################################" << endl;
        // cout << "#   1. show funcitons      2.send command  #" << endl;
        // cout << "############################################" << endl;
        // cout << "Please Select> ";
        // cin >> select;
        // if (select == 1)
        //     ShowHandler();
        // else if (select == 2)
        // {
        //     cout << "Enter Your Command> ";
        //     // 选择任务
        //     cin >> cmdid;
        //     // 选择进程
        //     int choice = rand() % slots.size();
        //     // 把任务给指定的进程
        //     SendAndWakeup(slots[choice].first, slots[choice].second, cmdid);
        // }
        // else
        // {
        //     break;
        // }
    }
    
    //关闭所有管道的写端，对应的子进程都会退出
    for(const auto& slot : slots)
    {
        close(slot.second);
    }

    for(const auto& slot : slots)
    {
        pid_t cpid = waitpid(slot.first, nullptr, 0);
        assert(cpid != -1);
        cout << "child process[" << cpid << "] exit!" << endl;
    }
    return 0;
}